﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Gumini.JulaDB.Engine;
using Gumini.JulaDB.Navigator.Logic;
using Gumini.JulaDB.Navigator.Views;
using ICSharpCode.AvalonEdit.Document;
using System.Diagnostics;

namespace Gumini.JulaDB.Navigator.ViewModels
{
    public class MainWindowViewModel : ObservableObject
    {
        #region Properties

        public ObservableCollection<LogMessage> LogMessages
        {
            get { return _logMessages; }
        }
        readonly ObservableCollection<LogMessage> _logMessages = new ObservableCollection<LogMessage>();

        public List<string> ColumnHeaders
        {
            get { return _columnHeaders; }
            private set
            {
                if (value != _columnHeaders)
                {
                    _columnHeaders = value;
                    RaisePropertyChanged("ColumnHeaders");
                }
            }
        }
        List<string> _columnHeaders;

        public List<ResultRowViewModel> Rows
        {
            get { return _rows; }
            private set
            {
                if (value != _rows)
                {
                    _rows = value;
                    RaisePropertyChanged("Rows");
                }
            }
        }
        List<ResultRowViewModel> _rows;

        public TextDocument Document
        {
            get { return _document; }
        }
        readonly TextDocument _document = new TextDocument();

        public ConnectionProvider Connection
        {
            get { return SimpleIoc.Default.GetInstance<ConnectionProvider>(); }
        }

        public ScriptProvider Script
        {
            get { return SimpleIoc.Default.GetInstance<ScriptProvider>(); }
        }

        public decimal ExecutionTime
        {
            get { return _executionTime; }
            private set
            {
                if (value != _executionTime)
                {
                    _executionTime = value;
                    RaisePropertyChanged("ExecutionTime");
                }
            }
        }
        decimal _executionTime;

        public bool UseOptimizer
        {
            get { return _useOptimizer; }
            set
            {
                if (value != _useOptimizer)
                {
                    _useOptimizer = value;
                    RaisePropertyChanged("UseOptimizer");
                }
            }
        }
        bool _useOptimizer = true;

        #endregion

        public MainWindowViewModel()
        {
            Script.FileOpened += (s, e) =>
                Document.Text = Script.Text;
        }

        #region Commands

        public Command OpenConnectionWindowCommand
        {
            get
            {
                if (_openConnectionWindowCommand == null)
                    _openConnectionWindowCommand = new Command(OpenConnectionWindow, CanOpenConnectionWindow);
                return _openConnectionWindowCommand;
            }
        }
        Command _openConnectionWindowCommand;

        private void OpenConnectionWindow()
        {
            var window = new ConnectionWindow()
            {
                DataContext = SimpleIoc.Default.GetInstance<ConnectionWindowViewModel>()
            };
            window.ShowDialog();
        }

        private bool CanOpenConnectionWindow()
        {
            return !Connection.IsConnected;
        }

        public Command ExecuteCommand
        {
            get
            {
                if (_executeCommand == null)
                    _executeCommand = new Command(Execute, CanExecute);
                return _executeCommand;
            }
        }
        Command _executeCommand;

        private void Execute()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            var result = Connection.Execute(this.Document.Text,
                useOptimizer: this.UseOptimizer);

            stopwatch.Stop();
            this.ExecutionTime = (decimal)stopwatch.ElapsedMilliseconds / 1000;

            foreach (var message in result.SelectMany(m => m.Messages))
                LogMessages.Add(message);

            BuildResultTables(result.Where(i => i.RecordSet != null).Select(i => i.RecordSet));
        }

        private bool CanExecute()
        {
            return // TODO
                //!string.IsNullOrWhiteSpace(this.UserInput) &&
                Connection.IsConnected;
        }

        public Command DisconnectCommand
        {
            get
            {
                if (_disconnectCommand == null)
                    _disconnectCommand = new Command(Disconnect, CanDisconnect);
                return _disconnectCommand;
            }
        }
        Command _disconnectCommand;

        private void Disconnect()
        {
            Connection.Disconnect();
        }

        private bool CanDisconnect()
        {
            return Connection.IsConnected;
        }

        public Command SaveScriptCommand
        {
            get
            {
                if (_saveScriptCommand == null)
                    _saveScriptCommand = new Command(SaveScript, CanSaveScript);
                return _saveScriptCommand;
            }
        }
        Command _saveScriptCommand;

        private void SaveScript()
        {
            Script.Text = Document.Text;
            Script.Save();
        }

        private bool CanSaveScript()
        {
            return Script.IsOpened;
        }

        #endregion

        #region Private Methods

        private void BuildResultTables(IEnumerable<RecordSet> results)
        {
            // for now we take the results of the last select statement
            var set = results.LastOrDefault();
            if (set == null)
            {
                // no selects, clear output tables
                this.Rows = null;
                this.ColumnHeaders = null;
            }
            else
            {
                this.Rows = set.Rows.Select(r => new ResultRowViewModel(r)).ToList();
                this.ColumnHeaders = set.Heading.Select(c => c.ColumnName).ToList();
            }
        }

        #endregion
    }
}
